home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / tvcolor.zip / COLORS.ASC < prev   
Text File  |  1991-08-27  |  14KB  |  310 lines

  1.  
  2.   Turbo Vision Palettes
  3.   =====================
  4.  
  5.   Objects in Turbo Vision can be grouped into two broad classes: those
  6.   which are descendants of TView (such as TWindow or TButton), and those
  7.   which are not (such as TCollection). The difference, of course, is
  8.   that objects which are descended from TView (also called "views" or
  9.   "view objects") are intended to be displayed on the computer's screen
  10.   at some point in their lifetimes. Every descendant of TView contains a
  11.   Draw method, which is executed whenever the view needs to redraw
  12.   itself. Although every view's Draw method is different, they all share
  13.   one characteristic: they call GetColor to determine what on-screen
  14.   colors to use when drawing the various parts of the view.
  15.  
  16.   GetColor in turn calls GetPalette, which returns a pointer to the
  17.   view's palette. What is a palette? In Turbo Vision, a palette acts as
  18.   a translation table. In much the same way that the ASCII code maps
  19.   byte values onto characters, a view's palette maps the set of colors
  20.   used by the view onto the palette of the view's owner.
  21.  
  22.   Let's look at the palette of the TLabel view as an example.
  23.   (It's shown at the end of the description of TLabel in the Turbo
  24.   Vision Guide.) We see that the palette has four entries, numbered 1
  25.   through 4. TLabel's Draw method knows that when it wants to draw
  26.   normal text, it should use color number 1. But it doesn't know what
  27.   color number 1 really is, and it doesn't care. It simply calls
  28.   GetColor (1) and uses the color that GetColor returns.
  29.  
  30.   GetColor calls GetPalette, which returns a pointer to TLabel's
  31.   palette. From the values contained in the palette, GetColor determines
  32.   that for TLabel, color number 1 is equivalent to TLabel's owner's
  33.   color number 7. GetColor then calls Owner^.GetColor (7); the owner
  34.   view then goes through the same procedure, using its own palette to
  35.   perform another level of translation, and so on, until the ultimate
  36.   owner is reached, which in most Turbo Vision programs is a
  37.   TApplication object (or descendant). The TApplication object is the
  38.   final color arbiter, and provides all of the views with the actual
  39.   video attributes to use.
  40.  
  41.   Let's trace through the TLabel color hierarchy: We've already
  42.   determined that TLabel color number 1 maps onto its owner's color
  43.   number 7. The description of TLabel's palette in the TV Guide states
  44.   that TLabel's palette maps onto the standard dialog palette. This
  45.   tells us that TLabel objects are intended to be owned by
  46.   (i.e., inserted into) TDialog objects. If we now turn to TDialog's
  47.   palette description, we see that color number 7 (called "Label
  48.   Normal") is mapped onto TDialog's owner's color number 38. Well,
  49.   dialog boxes are usually inserted into the desktop, so let's look at
  50.   TDeskTop's palette. When we do that, we see that TDeskTop doesn't have
  51.   a palette; this means that TDeskTop doesn't do any color
  52.   translation--TDialog's color number 38 "falls through" to TDeskTop's
  53.   owner's palette. Well, the desktop is owned by the application, so
  54.   we've reached the end of the chain. When TLabel's Draw method wants to
  55.   use color number 1, it eventually gets told to use the application's
  56.   color number 38.
  57.  
  58.   TApplication's palettes are not shown in the TV Guide, but we can find
  59.   them in the file APP.PAS in the TVISION directory. TApplication
  60.   actually uses one of three different palettes, depending on whether
  61.   the program is being run on a color, black and white, or monochrome
  62.   monitor. For the purposes of this example, we'll assume that we're
  63.   using a color monitor. If we locate the 38th entry in TApplication's
  64.   palette, we find that it is equal to $70. The upper nybble of the byte
  65.   gives the background color, and the lower nybble the foreground color,
  66.   according to the following table:
  67.  
  68.     0 - black      4 - red         8 - dark gray     C - light red
  69.     1 - blue       5 - magenta     9 - light blue    D - light magenta
  70.     2 - green      6 - brown       A - light green   E - yellow
  71.     3 - cyan       7 - light gray  B - light cyan    F - white
  72.  
  73.   So, we see that a normal label has black text on a light gray
  74.   background. All of the other colors may be tracked down in a similar
  75.   manner.
  76.  
  77.   What happens if rather than inserting a TLabel into a TDialog, we
  78.   insert it into a TWindow? Well, let's follow the mapping, again using
  79.   the "Normal Text" color: TLabel color number 1 -> TWindow color number
  80.   7 -> TApplication color number 14, 22, or 30, depending on whether the
  81.   window is a blue, cyan, or gray window, respectively. These entries
  82.   correspond to blue text on gray, blue text on green, or white text on
  83.   light gray. Obviously, none of these are the same as the black text on
  84.   light gray of a TLabel inserted into a TDialog. This points out a
  85.   universal truth of Turbo Vision palettes: If a view is designed to be
  86.   inserted into a particular type of owner view, inserting it into a
  87.   different type of owner will almost always result in a change in
  88.   color.
  89.  
  90.   Anyone who has played around much with Turbo Vision has encountered
  91.   the situation where a view is displayed in flashing white text on a
  92.   red background. This happens when a call to GetColor is made with a
  93.   color number that exceeds the size of the view's palette. For example,
  94.   let's see what happens when we insert a TListBox into a TWindow,
  95.   rather than a TDialog. (Note: The TV Guide says that TListBox's
  96.   palette maps onto the application palette. This is incorrect; it
  97.   actually maps onto TDialog's palette.) TListBox has a five-entry
  98.   palette which maps onto entries 26 through 29 in its owner's palette.
  99.   Well, lo and behold, a TWindow has only eight entries in its
  100.   palette--obtaining the 26th entry is impossible. In this situation,
  101.   GetColor returns the flashing white on red color to signal the error.
  102.   Here is a list of all of the entries in TApplication's palette, along
  103.   with the objects that use them:
  104.  
  105.    1 Background (DeskTop)
  106.    2 Text Normal (Menu)
  107.    3 Text Disabled (Menu)
  108.    4 Text Shortcut (Menu)
  109.    5 Selected Normal (Menu)
  110.    6 Selected Disabled (Menu)
  111.    7 Selected Shortcut (Menu)
  112.    8 Frame Passive (Blue Window)
  113.    9 Frame Active (Blue Window)
  114.   10 Frame Icon (Blue Window)
  115.   11 ScrollBar Page (Blue Window)
  116.   12 ScrollBar Reserved (Blue Window)
  117.   13 Scroller Normal Text (Blue Window)
  118.   14 Scroller Selected Text (Blue Window)
  119.   15 Reserved (Blue Window)
  120.   16 Frame Passive (Cyan Window)
  121.   17 Frame Active (Cyan Window)
  122.   18 Frame Icon (Cyan Window)
  123.   19 ScrollBar Page (Cyan Window)
  124.   20 ScrollBar Reserved (Cyan Window)
  125.   21 Scroller Normal Text (Cyan Window)
  126.   22 Scroller Selected Text (Cyan Window)
  127.   23 Reserved (Cyan Window)
  128.   24 Frame Passive (Gray Window)
  129.   25 Frame Active (Gray Window)
  130.   26 Frame Icon (Gray Window)
  131.   27 ScrollBar Page (Gray Window)
  132.   28 ScrollBar Reserved (Gray Window)
  133.   29 Scroller Normal Text (Gray Window)
  134.   30 Scroller Selected Text (Gray Window)
  135.   31 Reserved (Gray Window)
  136.   32 Frame Passive (Dialog)
  137.   33 Frame Active (Dialog)
  138.   34 Frame Icon (Dialog)
  139.   35 ScrollBar Page (Dialog)
  140.   36 ScrollBar Controls (Dialog)
  141.   37 StaticText (Dialog)
  142.   38 Label Normal (Dialog)
  143.   39 Label Highlight(Dialog)
  144.   40 Label Shortcut (Dialog)
  145.   41 Button Normal (Dialog)
  146.   42 Button Default (Dialog)
  147.   43 Button Selected (Dialog)
  148.   44 Button Disabled (Dialog)
  149.   45 Button Shortcut (Dialog)
  150.   46 Button Shadow (Dialog)
  151.   47 Cluster Normal (Dialog)
  152.   48 Cluster Selected (Dialog)
  153.   49 Cluster Shortcut (Dialog)
  154.   50 InputLine Normal (Dialog)
  155.   51 InputLine Selected (Dialog)
  156.   52 InputLine Arrows (Dialog)
  157.   53 History Arrow (Dialog)
  158.   54 History Sides (Dialog)
  159.   55 HistoryWindow ScrollBar page (Dialog)
  160.   56 HistoryWindow ScrollBar controls (Dialog)
  161.   57 ListViewer Normal (Dialog)
  162.   58 ListViewer Focused (Dialog)
  163.   59 ListViewer Selected (Dialog)
  164.   60 ListViewer Divider (Dialog)
  165.   61 InfoPane (Dialog)
  166.   62 Reserved (Dialog)
  167.   63 Reserved (Dialog)
  168.  
  169.   What about changing colors in Turbo Vision? If all you want to do is
  170.   change the color of all instances of an object, say, by making all of
  171.   your TButtons cyan instead of green, you've got it easy. You just
  172.   change the appropriate entries in TApplication's palette (41 through
  173.   46), and you're set.
  174.  
  175.   That was easy. Now, what about creating a new, unique view which is
  176.   unlike any predefined Turbo Vision objects? How will we color it?
  177.   Let's say we want to insert our new view (call it a TNewView) into a
  178.   TDialog, and we want to use two different colors, one for normal text
  179.   and one for highlighted text. First, we add two entries to
  180.   TApplication's palette (numbers 64 and 65) that will correspond to the
  181.   two colors used by our new view. For the purposes of this example,
  182.   we'll say we want blue on light gray ($71) for normal text and light
  183.   green on light gray ($7A) for highlighted text (assuming a color
  184.   monitor). Our TApplication palette will now look like this:
  185.  
  186.   CColor = #$71#$70#$78#$74#$20#$28#$24#$17#$1F#$1A#$31#$31#$1E#$71#$00 +
  187.            #$37#$3F#$3A#$13#$13#$3E#$21#$00#$70#$7F#$7A#$13#$13#$70#$7F +
  188.            #$00#$70#$7F#$7A#$13#$13#$70#$70#$7F#$7E#$20#$2B#$2F#$78#$2E +
  189.            #$70#$30#$3F#$3E#$1F#$2F#$1A#$20#$72#$31#$31#$30#$2F#$3E#$31 +
  190.            #$13#$00#$00#$71#$7A;  { <- the last two are the new entries }
  191.  
  192.   We must make similar changes in the black & white and monochrome
  193.   palettes, of course. Next, since we will be inserting TNewView into a
  194.   TDialog, we need to override TDialog's GetPalette method so that it
  195.   will supply GetColor with the proper palette:
  196.  
  197.     const
  198.       CNewDialog = CDialog + #64#65;
  199.  
  200.     type
  201.       TNewDialog = object (TDialog)
  202.                      function GetPalette: PPalette; virtual;
  203.                    end;
  204.     .
  205.     .
  206.     .
  207.     function TNewDialog.GetPalette: PPalette;
  208.     const
  209.       P: String[Length (CNewDialog)] = CNewDialog;
  210.     begin
  211.       GetPalette := @P;
  212.     end;
  213.  
  214.   Since we added our two new colors to the end of the standard TDialog
  215.   palette, which contains 32 entries, they will be the 33rd and 34th
  216.   entries in TNewDialog's palette. Now we have to define our TNewView so
  217.   that it maps onto the 33rd and 34th entry of its owner's palette:
  218.  
  219.     const
  220.       CNewView = #33#34;
  221.  
  222.     type
  223.       TNewView = object (TView)
  224.                    function GetPalette: PPalette; virtual;
  225.                    .
  226.                    .
  227.                    .
  228.                  end;
  229.  
  230.     function TNewView.GetPalette: PPalette;
  231.     const
  232.       P: String[Length (CNewView)] = CNewView;
  233.     begin
  234.       GetPalette := @P;
  235.     end;
  236.  
  237.   There. That wasn't so bad, was it? When TNewView's Draw method asks
  238.   for color number 1, it will get color number 64 from TApplication's
  239.   palette; similarly, color number 2 leads to TApplication's color
  240.   number 65. If we ever want to change the colors of our TNewView
  241.   object, we simply change the entries in TApplication's palette.
  242.  
  243.   Okay, let's try something a bit trickier. Let's say we want to insert
  244.   a view into an owner which is not of the "correct" type. We already
  245.   know that unless we modify the palettes and associated methods, the
  246.   colors will come out wrong. The most general solution to the problem
  247.   is to define a new object type, as in the previous example. Thus, if
  248.   we wanted to insert a TButton into a TWindow, we would define a
  249.   descendant of TButton (called TWindowButton, perhaps) and follow the
  250.   same steps we performed above to give it a set of colors to use.
  251.  
  252.   In some cases, we don't need to add to TApplication's palette. In the
  253.   previous example, if all we want to do is put a button in a window,
  254.   and we want the button to look just like an ordinary TButton inserted
  255.   into a TDialog, we can use the same TApplication palette entries (41
  256.   through 46):
  257.  
  258.     const
  259.       CNewWindow = CGrayWindow + #41#42#43#44#45#46;
  260.       CWindowButton = #9#10#11#12#13#13#13#14;
  261.     type
  262.       TNewWindow = object (TWindow)
  263.                      function GetPalette: PPalette; virtual;
  264.                    end;
  265.  
  266.     TWindowButton = object (TButton)
  267.                       function GetPalette: PPalette; virtual;
  268.                     end;
  269.  
  270.   The GetPalette method code is analogous to that of the previous
  271.   example. Now, when TWindowButton.Draw asks for color number 2, it is
  272.   mapped to TNewWindow's color number 10, which is mapped to
  273.   TApplication's color number 42, just as if it had been a TButton
  274.   inserted into a TDialog. Note that I used CGrayWindow as the basis for
  275.   CNewWindow's palette. Since a TButton is normally inserted into a
  276.   TDialog, two of its colors (44 and 46) use a gray background. If you
  277.   wanted to put buttons into cyan or blue windows, you would need to use
  278.   the more general method of adding to TApplication's palette, as in the
  279.   previous example.
  280.  
  281.   Last but not least, what about objects which can be instantiated with
  282.   one of several palettes? TWindow is a good example of this type of
  283.   object; you can have windows with blue, gray, or cyan color schemes.
  284.   One of TWindow's fields (Palette) is used to indicate which color
  285.   scheme GetPalette should return. TWindow.GetPalette might look
  286.   something like this:
  287.  
  288.     function TWindow.GetPalette: PPalette;
  289.     const
  290.       PGray: string[Length (CGrayWindow)] = CGrayWindow;
  291.       PCyan: string[Length (CCyanWindow)] = CCyanWindow;
  292.       PBlue: string[Length (CBlueWindow)] = CBlueWindow;
  293.     begin
  294.       case Palette of
  295.         wpGrayWindow: GetPalette = @PGray;
  296.         wpCyanWindow: GetPalette = @PCyan;
  297.         wpBlueWindow: GetPalette = @PBlue;
  298.       end;
  299.     end;
  300.  
  301.   You can use the same technique with any objects of your own devising.
  302.  
  303.   Well, that's about it for Turbo Vision palettes. Are you thoroughly
  304.   confused yet? Just remember: figuring out what color a view is going
  305.   to be drawn with is as simple as tracing the color mapping up the
  306.   ownership hierarchy, until you reach the TApplication object.
  307.  
  308.   Please direct comments or suggestions to Steve Schafer [71121,1771].
  309.  
  310.